home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / popcli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  9.7 KB  |  464 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  5.  *      with later releases (NOS0522).
  6.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  7.  *
  8.  *    Some code culled from previous releases of SMTP.
  9.  *
  10.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  11.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  12.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  13.  *    Permission granted for non-commercial copying and use, provided
  14.  *      this notice is retained.
  15.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  16.  *      also rebuilt locking mechanism
  17.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  18.  *    Permission granted for non-commercial copying and use, provided
  19.  *    this notice is retained.
  20.  */
  21. #include <stdio.h>
  22. #include <fcntl.h>
  23. #include <time.h>
  24. #include <setjmp.h>
  25. #ifdef UNIX
  26. #include <sys/types.h>
  27. #endif
  28. #ifdef    __TURBOC__
  29. #include <dir.h>
  30. #include <io.h>
  31. #endif
  32. #include "global.h"
  33. #ifdef    ANSIPROTO
  34. #include <stdarg.h>
  35. #endif
  36. #include "mbuf.h"
  37. #include "cmdparse.h"
  38. #include "proc.h"
  39. #include "socket.h"
  40. #include "timer.h"
  41. #include "netuser.h"
  42. #include "dirutil.h"
  43. #include "files.h"
  44. #include "pop.h"
  45. #include "commands.h"
  46.  
  47. extern char Badhost[];
  48.  
  49. /* POP client control block */
  50.  
  51. struct pop_ccb {
  52.     int    socket;        /* socket for this connection */
  53.     char    state;        /* client state */
  54. #define       CALL        0
  55. #define       NMBR        3
  56. #define       SIZE        5
  57. #define       XFER        8
  58. #define       EXIT        10
  59.     char    buf[BUF_LEN],    /* tcp input buffer */
  60.         count;        /* input buffer length */
  61.     int    folder_len;    /* number of msgs in current folder */
  62.     long    msg_len;    /* length of current msg */
  63.     int    msg_num;    /* current message number */
  64. } *ccb;
  65.  
  66. #define NULLCCB        (struct pop_ccb *)0
  67.  
  68. static int Popquiet = 0;
  69.  
  70. static struct timer  popcli_t;
  71. static int32 mailhost;
  72. static char    mailbox_name[10],
  73.         mailbox_pathname[BUF_LEN],
  74.         username[20],
  75.         password[20],
  76.         Workfile_name[] ="mbox.pop";
  77.  
  78. static int domailbox __ARGS((int argc,char *argv[],void *p));
  79. static int domailhost __ARGS((int argc,char *argv[],void *p));
  80. static int douserdata __ARGS((int argc,char *argv[],void *p));
  81. static int doquiet __ARGS((int argc,char *argv[],void *p));
  82. static int dotimer __ARGS((int argc,char *argv[],void *p));
  83. static struct pop_ccb     *new_ccb __ARGS((void));
  84. static void delete_ccb __ARGS((void));
  85. static void pop_send __ARGS((int unused,void *cb1,void *p));
  86. static int popkick __ARGS((int argc,char *argv[],void *p));
  87.  
  88. static struct cmds Popcmds[] = {
  89.     "mailbox",    domailbox,    0,    0,    NULLCHAR,
  90.     "mailhost",    domailhost,    0,    0,    NULLCHAR,
  91.     "kick",        popkick,    0,    0,    NULLCHAR,
  92.     "quiet",    doquiet,    0,    0,    NULLCHAR,
  93.     "timer",    dotimer,    0,    0,    NULLCHAR,
  94.     "userdata",    douserdata,    0,    0,    NULLCHAR,
  95.     NULLCHAR,
  96. };
  97.  
  98.  
  99. /* Command string specifications */
  100.  
  101. static char ackd_cmd[] = "ACKD\n",
  102. #ifdef POP_FOLDERS
  103.     fold_cmd[] = "FOLD %s\n",
  104. #endif
  105.     login_cmd[] = "HELO %s %s\n",
  106. /*      nack_cmd[]      = "NACK\n",     /* Not implemented */
  107.     quit_cmd[]      = "QUIT\n",
  108.     read_cur_cmd[]  = "READ\n",
  109.     retr_cmd[]      = "RETR\n";
  110.  
  111. /* Response string keys */
  112.  
  113. static char *greeting_rsp  = "+ POP2 ";
  114.  
  115. FILE    *fd;
  116. #define    NULLFILE    (FILE *)0
  117.  
  118. int dopop(argc,argv,p)
  119. int argc;
  120. char *argv[];
  121. void *p;
  122. {
  123.     return subcmd(Popcmds,argc,argv,p);
  124. }
  125.  
  126. static int domailbox(argc,argv,p) 
  127. int argc;
  128. char *argv[];
  129. void *p;
  130. {
  131.     if(argc < 2) {
  132.         if(mailbox_name[0] == '\0')
  133.             tprintf("maibox name not set yet\n");
  134.         else
  135.             tprintf("%s\n",mailbox_name);
  136.     } else {
  137.         strncpy(mailbox_name,argv[1],10);
  138.     }
  139.  
  140.     return 0;
  141. }
  142.  
  143. static int domailhost(argc,argv,p)
  144. int argc;
  145. char *argv[];
  146. void *p;
  147. {
  148.     int32 n;
  149.  
  150.     if(argc < 2) {
  151.         tprintf("%s\n",inet_ntoa(mailhost));
  152.     } else
  153.         if((n = resolve(argv[1])) == 0) {
  154.             tprintf(Badhost,argv[1]);
  155.             return 1;
  156.         } else
  157.             mailhost = n;
  158.  
  159.     return 0;
  160. }
  161.  
  162. static int doquiet(argc,argv,p)
  163. int argc;
  164. char *argv[];
  165. void *p;
  166. {
  167.     return setbool(&Popquiet,"POP quiet",argc,argv);
  168. }
  169.  
  170. static int douserdata(argc,argv,p)
  171. int argc;
  172. char *argv[];
  173. void *p;
  174. {
  175.     if (argc < 2)
  176.         tprintf("%s\n",username);
  177.     else if (argc != 3) {
  178.         tprintf("Usage: pop userdata <username> <password>\n");
  179.         return 1;
  180.     } else {
  181.         sscanf(argv[1],"%18s",username);
  182.         sscanf(argv[2],"%18s",password);
  183.     }
  184.  
  185.     return 0;
  186. }
  187.  
  188. /* Set scan interval */
  189.  
  190. static int dotimer(argc,argv,p)
  191. int argc;
  192. char *argv[];
  193. void *p;
  194. {
  195.     int poptick();
  196.  
  197.  
  198.     if(argc < 2) {
  199.         tprintf("%lu/%lu\n",
  200.                (popcli_t.start - popcli_t.count)/(1000/MSPTICK),
  201.                popcli_t.start/(1000/MSPTICK));
  202.         return 0;
  203.     }
  204.  
  205.     popcli_t.func  = (void (*)())poptick;          /* what to call on timeout */
  206.     popcli_t.arg   = NULL;                /* dummy value */
  207.     popcli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  208.     start_timer(&popcli_t);                /* and fire it up */
  209.     return 0;
  210. }
  211.  
  212. static int popkick(argc,argv,p)
  213. int argc;
  214. char *argv[];
  215. void *p;
  216. {
  217.     poptick(NULL);
  218.     return 0;
  219. }
  220.  
  221. int poptick(t)
  222. void *t;
  223. {
  224.     if (ccb == NULLCCB) {
  225.  
  226.         /* Don't start if any of the required parameters have not been specified */
  227.  
  228.         if (mailhost == 0) {
  229.             tprintf("mailhost not defined yet.(pop mailhost <host>)\n");
  230.             return 0;
  231.         }
  232.  
  233.         if (mailbox_name[0] == '\0') {
  234.             tprintf("mailbox name not defined yet.(pop mailbox <name>)\n");
  235.             return 0;
  236.         }
  237.  
  238.         if (username[0] == '\0') {
  239.             tprintf("username not defined yet. (pop user <name> <pass>)\n");
  240.             return 0;
  241.         }
  242.  
  243.         if (password[0] == '\0') {
  244.             tprintf(" Unknown password\n");
  245.             return 0;
  246.         }
  247.  
  248.         if ((ccb = new_ccb()) == NULLCCB) {
  249.             fprintf(stderr,"*** Unable to allocate CCB");
  250.             return 0;
  251.         }
  252.  
  253.         newproc("Auto-POP Client",1024,pop_send,0,ccb,NULL);
  254.     }
  255.  
  256.     /* Restart timer */
  257.  
  258.     start_timer(&popcli_t);
  259.     return 0;
  260. }
  261.  
  262. /* this is the master state machine that handles a single SMTP transaction */
  263. /* it is called with a queue of jobs for a particular host. */
  264.  
  265. static void pop_send(unused,cb1,p) 
  266. int unused;
  267. void *cb1;
  268. void *p;
  269. {
  270.     char *cp;
  271.     struct sockaddr_in fsocket;
  272.     struct pop_ccb    *ccb;
  273.     void pop_csm(struct pop_ccb *);
  274.     void quit_session(struct pop_ccb *);
  275.  
  276.     ccb = (struct pop_ccb *)cb1;
  277.     fsocket.sin_family = AF_INET;
  278.     fsocket.sin_addr.s_addr = mailhost;
  279.     fsocket.sin_port = IPPORT_POP;
  280.  
  281.     ccb->socket = socket(AF_INET,SOCK_STREAM,0);
  282.  
  283.     ccb->state = CALL;
  284.  
  285.     if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) == 0) {
  286.         mainlog(ccb->socket,"Connected to mailhost %s", inet_ntoa(mailhost));
  287.     } else {
  288.         cp = sockerr(ccb->socket);
  289.         mainlog(ccb->socket,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  290.             (cp != NULLCHAR)? cp: "");
  291.     }
  292.  
  293.     while(1) {
  294.         if (recvline(ccb->socket,ccb->buf,BUF_LEN) == -1)
  295.             goto quit;
  296.  
  297.         rip(ccb->buf);
  298.         pop_csm(ccb);
  299.         if (ccb->state == EXIT)
  300.             goto quit;
  301.     }
  302. quit:
  303.     mainlog(ccb->socket,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  304.     (void) close_s(ccb->socket);
  305.     if (fd != NULLFILE)
  306.         fclose(fd);
  307.     delete_ccb();
  308. }
  309.  
  310. /* free the message struct and data */
  311.  
  312. static void delete_ccb()
  313. {
  314.     if (ccb == NULLCCB)
  315.         return;
  316.  
  317.     free((char *)ccb);
  318.     ccb = NULLCCB;
  319. }
  320.  
  321. /* create a new  pop control block */
  322.  
  323. static struct pop_ccb *new_ccb()
  324. {
  325.     register struct pop_ccb *ccb;
  326.  
  327.     if ((ccb = (struct pop_ccb *) callocw(1,sizeof(struct pop_ccb))) == NULLCCB)
  328.         return(NULLCCB);
  329.     return(ccb);
  330. }
  331.  
  332. /* ---------------------- pop client code starts here --------------------- */
  333.  
  334. void pop_csm(ccb)
  335. struct pop_ccb    *ccb;
  336. {
  337.     FILE *mf;
  338.  
  339.     int mlock (char *,char *);
  340.     int rmlock (char * ,char *);
  341.     /* int mlock __ARGS((char *dir,char *id));   */
  342.     /* int rmlock __ARGS((char *dir,char *id));   */
  343.  
  344.  
  345.     switch(ccb->state) {
  346.     case CALL:
  347.         if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  348.              (void)usprintf(ccb->socket,login_cmd,username,password);
  349.             ccb->state = NMBR;
  350.         } else
  351.             (void) quit_session(ccb);
  352.         break;
  353.  
  354.     case NMBR:
  355.  
  356.         switch (ccb->buf[0]) {
  357.         case '#':
  358.             if ((fd = fopen(Workfile_name,"a+")) == NULLFILE) {
  359.                 perror("Unable to open work file");
  360.                 quit_session(ccb);
  361.                 return;
  362.             }
  363.  
  364.             fseek(fd,0,0);
  365.             ccb->folder_len = atoi(&(ccb->buf[1]));
  366.             (void)usprintf(ccb->socket,read_cur_cmd);
  367.             ccb->state = SIZE;
  368.             break;
  369.  
  370.         case '+':
  371.  
  372.             /* If there is no mail (the only time we get a "+"
  373.              * response back at this stage of the game),
  374.              * then just close out the connection, because
  375.              * there is nothing more to do!! */
  376.  
  377.         default:
  378.             quit_session(ccb);
  379.             break;
  380.         }
  381.     break;
  382.  
  383.     case SIZE:
  384.         if (ccb->buf[0] == '=') {
  385.             ccb->msg_len = atol(&(ccb->buf[1]));
  386.             if (ccb->msg_len > 0) {
  387.                 (void)usprintf(ccb->socket,retr_cmd);
  388.  
  389.                 ccb->state = XFER;
  390.             } else {
  391.                 mainlog(ccb->socket,"POP client retrieved %d messages",
  392.                         ccb->folder_len);
  393.  
  394.                 /* All done, so do local cleanup */
  395.  
  396.                 if (mlock(Mailspool,mailbox_name)) {
  397.                     tprintf("\n*** Local mailbox locked, new mail in file %s\n",
  398.                          Workfile_name);
  399.                     quit_session(ccb);
  400.                     return;
  401.                 }
  402.  
  403.                 sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  404.                     mailbox_name);
  405.                 if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  406.                     tprintf("\n*** Unable to open local mailbox, new mail in file %s\n",
  407.                            Workfile_name);
  408.                     quit_session(ccb);
  409.                     return;
  410.                 }
  411.  
  412.                 fseek(fd,0,0);
  413.  
  414.                 while (!feof(fd)) {
  415.                     if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  416.                         fputs(ccb->buf,mf);
  417.                     }
  418.                 }
  419.                 fclose(mf);
  420.                 fclose(fd);
  421.                 fd = NULL;
  422.                 printf("\a\x1b[32mNew mail arrived for '\x1b[33m%s\x1b[32m' from mailhost <\x1b[33m%s\x1b[32m>%c\x1b[0m\n",
  423.                     mailbox_name, inet_ntoa(mailhost),
  424.                     Popquiet ? ' ' : '\007');
  425.                 rmlock(Mailspool,mailbox_name);
  426.                 unlink(Workfile_name);
  427.                 quit_session(ccb);
  428.             }
  429.         } else
  430.             quit_session(ccb);
  431.         break;
  432.  
  433.         case XFER:
  434.             fprintf(fd,"%s\n",ccb->buf);
  435.  
  436.             ccb->msg_len -= (long)(strlen(ccb->buf)+2);    /* Add CRLF */
  437.  
  438.             if (ccb->msg_len > 0)
  439.                 return;
  440.  
  441.             (void)usprintf(ccb->socket,ackd_cmd);
  442.  
  443.             ccb->msg_num++;
  444.             ccb->state = SIZE;
  445.             break;
  446.  
  447.         case EXIT:
  448.             if (fd != NULLFILE)
  449.                 fclose(fd);
  450.             break;
  451.  
  452.         default:
  453.             break;
  454.     }
  455. }
  456.  
  457. void quit_session(ccb)
  458. struct pop_ccb    *ccb;
  459. {
  460.     (void)usprintf(ccb->socket,quit_cmd);
  461.  
  462.     ccb->state  = EXIT;
  463. }
  464.